<?php
namespace addon\wechat_config\logic;
// +----------------------------------------------------------------------
// | Author: xiaojun <920668625@qq.com>
// +----------------------------------------------------------------------
use app\common\logic\LogicBase;
use think\Db;
use tpfcore\Core;
use think\Cache;

class WechatFunc extends LogicBase
{

	/**
	 * 素材类型
	 * @return array
	 */
	static public function MaterialType(){
		return [
			//'media' =>'图文消息',
            'news' =>'图文消息',
			'text'  =>'文本',
			'image' =>'图片',
			'voice' =>'语音',
			'video' =>'视频'
		];
	}

	/**
	 * 获取表情列表
	 * @return array
	 */
	static public function getEemojList(){
        return Db::name('WechatEmoji')->order('emoji asc')->select();
    }

    /**
     * 获取单个表情
     * @return array
     */
    static public function getEemoj($emoji=''){
        return Db::name('WechatEmoji')->where('emoji',$emoji)->find();
    }

    /**
     * 判断是不是一个图片文件
     * @param  string  $img 图片地址
     * @return boolean
     */
    static public function is_image($img='')
    {
        return in_array(strtolower(self::get_fileext($img)),array('gif','jpg','jpeg','png','bmp'));
    }

	/**
	 * 判断是不是一个语音文件
	 * @param  string  $voice 语音地址
	 * @return boolean
	 */
	static public function is_voice($voice=''){
		return in_array(strtolower(self::get_fileext($voice)),array('mp3','wma','wav','amr'));
	}

    /**
     * 判断是不是一个视频文件
     * @param  string  $video 视频地址
     * @return boolean
     */
    static public function is_video($video='')
    {
        return in_array(strtolower(self::get_fileext($video)),array('flv','swf','mp4'));
    }

    /**
     * 获取文件后缀 如 jpg/gif/exe 等
     * @param  string $file 文件路径
     * @return string       文件后缀
     */
    static public function get_fileext($file='')
    {
        return strtolower(substr(strrchr($file,'.'),1));
    }

    /**
     * 对字符串或数组进行 addslashes 过滤 
     * @param  [type] $str 要过滤的字符串或数组
     * @return data
     */
    static public function tpf_addslashes($str)
    {
        if(!is_array($str) && !is_object($str))
        {
            return addslashes($str);
        }
        foreach($str as $key=>$value)
        {
            $str[$key]=self::tpf_addslashes($value);
        }
        return $str;
    }

    /*=======================消息处理=======================*/
    //回复文本消息
    static public function transmitText($object, $content)
    {
        if (!isset($content) || empty($content)){
            return '';
        }

        $xmlTpl = "<xml>
            <ToUserName><![CDATA[%s]]></ToUserName>
            <FromUserName><![CDATA[%s]]></FromUserName>
            <CreateTime>%s</CreateTime>
            <MsgType><![CDATA[text]]></MsgType>
            <Content><![CDATA[%s]]></Content>
        </xml>";
        $result = sprintf($xmlTpl, $object->FromUserName, $object->ToUserName, time(), $content);

        return $result;
    }

    //回复图文消息
    static public function transmitNews($object, $newsArray)
    {
        if(!is_array($newsArray)){
            return '';
        }
        $itemTpl = "<item>
            <Title><![CDATA[%s]]></Title>
            <Description><![CDATA[%s]]></Description>
            <PicUrl><![CDATA[%s]]></PicUrl>
            <Url><![CDATA[%s]]></Url>
        </item>";
        $item_str = "";
        foreach ($newsArray as $item){
            $item_str .= sprintf($itemTpl, $item['Title'], $item['Description'], $item['PicUrl'], $item['Url']);
        }
        $xmlTpl = "<xml>
            <ToUserName><![CDATA[%s]]></ToUserName>
            <FromUserName><![CDATA[%s]]></FromUserName>
            <CreateTime>%s</CreateTime>
            <MsgType><![CDATA[news]]></MsgType>
            <ArticleCount>%s</ArticleCount>
            <Articles>$item_str</Articles>
        </xml>";

        $result = sprintf($xmlTpl, $object->FromUserName, $object->ToUserName, time(), count($newsArray));
        return $result;
    }

    //回复音乐消息
    static public function transmitMusic($object, $musicArray)
    {
        if(!is_array($musicArray)){
            return '';
        }
        $itemTpl = "<Music>
            <Title><![CDATA[%s]]></Title>
            <Description><![CDATA[%s]]></Description>
            <MusicUrl><![CDATA[%s]]></MusicUrl>
            <HQMusicUrl><![CDATA[%s]]></HQMusicUrl>
        </Music>";

        $item_str = sprintf($itemTpl, $musicArray['Title'], $musicArray['Description'], $musicArray['MusicUrl'], $musicArray['HQMusicUrl']);

        $xmlTpl = "<xml>
            <ToUserName><![CDATA[%s]]></ToUserName>
            <FromUserName><![CDATA[%s]]></FromUserName>
            <CreateTime>%s</CreateTime>
            <MsgType><![CDATA[music]]></MsgType>
            $item_str
        </xml>";

        $result = sprintf($xmlTpl, $object->FromUserName, $object->ToUserName, time());
        return $result;
    }

    //回复图片消息
    static public function transmitImage($object, $imageArray)
    {
        $itemTpl = "<Image>
            <MediaId><![CDATA[%s]]></MediaId>
        </Image>";

        $item_str = sprintf($itemTpl, $imageArray['MediaId']);

        $xmlTpl = "<xml>
            <ToUserName><![CDATA[%s]]></ToUserName>
            <FromUserName><![CDATA[%s]]></FromUserName>
            <CreateTime>%s</CreateTime>
            <MsgType><![CDATA[image]]></MsgType>
            $item_str
        </xml>";

        $result = sprintf($xmlTpl, $object->FromUserName, $object->ToUserName, time());
        return $result;
    }

    //回复语音消息
    static public function transmitVoice($object, $voiceArray)
    {
        $itemTpl = "<Voice>
            <MediaId><![CDATA[%s]]></MediaId>
        </Voice>";

        $item_str = sprintf($itemTpl, $voiceArray['MediaId']);
        $xmlTpl = "<xml>
            <ToUserName><![CDATA[%s]]></ToUserName>
            <FromUserName><![CDATA[%s]]></FromUserName>
            <CreateTime>%s</CreateTime>
            <MsgType><![CDATA[voice]]></MsgType>
            $item_str
        </xml>";

        $result = sprintf($xmlTpl, $object->FromUserName, $object->ToUserName, time());
        return $result;
    }

    //回复视频消息
    static public function transmitVideo($object, $videoArray)
    {
        $itemTpl = "<Video>
            <MediaId><![CDATA[%s]]></MediaId>
            <ThumbMediaId><![CDATA[%s]]></ThumbMediaId>
            <Title><![CDATA[%s]]></Title>
            <Description><![CDATA[%s]]></Description>
        </Video>";

        $item_str = sprintf($itemTpl, $videoArray['MediaId'], $videoArray['ThumbMediaId'], $videoArray['Title'], $videoArray['Description']);

        $xmlTpl = "<xml>
            <ToUserName><![CDATA[%s]]></ToUserName>
            <FromUserName><![CDATA[%s]]></FromUserName>
            <CreateTime>%s</CreateTime>
            <MsgType><![CDATA[video]]></MsgType>
            $item_str
        </xml>";

        $result = sprintf($xmlTpl, $object->FromUserName, $object->ToUserName, time());
        return $result;
    }

    //回复多客服消息
    static public function transmitService($object)
    {
        $xmlTpl = "<xml>
            <ToUserName><![CDATA[%s]]></ToUserName>
            <FromUserName><![CDATA[%s]]></FromUserName>
            <CreateTime>%s</CreateTime>
            <MsgType><![CDATA[transfer_customer_service]]></MsgType>
        </xml>";
        
        $result = sprintf($xmlTpl, $object->FromUserName, $object->ToUserName, time());
        return $result;
    }

    /**
     * 获取XML字符串中的键对应的值
     * @param  string $start 起始键值
     * @param  string $end   结束键值
     * @param  string $xml   xml数据
     * @return string        获取到的值
     */
    static public function getXmlVal($start='',$end='',$xml='')
    {
        preg_match('/'.$start.'(.*)'.$end.'/i',$xml,$matches);
        return str_replace(array('<![CDATA[',']]>'),'',$matches[1]);
    }

    /**
     * 字节转Emoji表情
     * @param  string $cp 16进制的表情编码
     * @return 表情符
     */
    static public function bytesToEmoji($cp)
    {
        $cp = hexdec($cp);
        if ($cp > 0x10000){       # 4 bytes
            return chr(0xF0 | (($cp & 0x1C0000) >> 18)).chr(0x80 | (($cp & 0x3F000) >> 12)).chr(0x80 | (($cp & 0xFC0) >> 6)).chr(0x80 | ($cp & 0x3F));
        }else if ($cp > 0x800){   # 3 bytes
            return chr(0xE0 | (($cp & 0xF000) >> 12)).chr(0x80 | (($cp & 0xFC0) >> 6)).chr(0x80 | ($cp & 0x3F));
        }else if ($cp > 0x80){    # 2 bytes
            return chr(0xC0 | (($cp & 0x7C0) >> 6)).chr(0x80 | ($cp & 0x3F));
        }else{                    # 1 byte
            return chr($cp);
        }
    }

    /**
     * 格式化url路径
     * @param  string $url $str url路径
     * @return string      完整链接
     */
    static public function format_url($url=''){
        return strtolower(($url && preg_match('/^http(s)?:\\/\\/.+/',$url))?$url:SITE_PATH.$url);
        //return strtolower(($url && strpos($url,'http://')!==false || strpos($url,'https://')!==false)?$url:SITE_PATH.$url);

    }

	/**
	 * http请求
	 * @param  string $url  请求链接
	 * @param  string $data json 格式数据
	 * @return data
	 */
	static public function http_request($url, $data = null){
        $curl = curl_init();
        curl_setopt($curl, CURLOPT_URL, $url);
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);

        if (!empty($data)){
            curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "POST");
            curl_setopt($curl, CURLOPT_POST, 1);
            curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
            curl_setopt($curl, CURLOPT_HTTPHEADER, array(
                'Content-Type: application/json',
                'Content-Length: ' . strlen($data))
            );
        }
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
        curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1);
        $output = curl_exec($curl);
        curl_close($curl);
        return $output;
    }

    /**
     * 附文件上传的请求
     * @param  string $url  [description]
     * @param  array  $data [description]
     * @return data
     * if(class_exists('CURLFile')){
            $field = ['media' => new \CURLFile($FilePath)];
        }else{
            $field = ['media' => '@' . $FilePath];
        }
        http_media_request($url,$field)
     */
    static public function http_media_request($url, $data = array()){
		$curl = curl_init();
		if(class_exists('CURLFile')) {
			curl_setopt($curl, CURLOPT_SAFE_UPLOAD, true);
		}else{
			if(defined('CURLOPT_SAFE_UPLOAD')) {
				curl_setopt($curl, CURLOPT_SAFE_UPLOAD, false);
			}
		}
		curl_setopt($curl,CURLOPT_URL,$url);
		curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
		curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
		curl_setopt($curl,CURLOPT_RETURNTRANSFER,true);
        curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "POST");
		curl_setopt($curl,CURLOPT_POST,true);
		curl_setopt($curl,CURLOPT_POSTFIELDS,$data);
		$result = curl_exec($curl);
		curl_close($curl);

		return $result;
	}

    static public function getAccessToken($is_throw = true){
    	
    	$info = Db::name('WechatConfig')->order('id desc')->value('value');
        $info = json_decode($info,true);

    	if(empty($info) || empty($info['wechat_appid']) || empty($info['wechat_appsecret'])){
    		throw new \Exception("请先配置好微信公众号");exit;
    	}
        $appid     = $info['wechat_appid'];
        $appsecret = $info['wechat_appsecret'];

        if(Cache::has('access_token')){
            return Cache::get('access_token');
        }else{
            $url='https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid='.$appid.'&secret='.$appsecret;
            $output=json_decode(self::http_request($url),true);
            if(!isset($output['errcode'])){
                $access_token=$output['access_token'];
                Cache::set('access_token',$access_token,3600);
                return $access_token;
            }else{
                if($is_throw){
                    throw new \Exception($output['errmsg']);
                }else{
                    return false;
                } 
            }
        }
    }

    /**
     * 素材管理通用文件上传
     * @return array
     */
    static public function upload(){
        if(request()->file()){
            $param = request()->param();
            $size  = 10*1024*1024; //最大上传为10M
            $ext   = 'jpg,png,gif,mp3,wma,wav,amr,mp4'; //素材管理通用上传
            //可上传多张图片，名字任意
            $urls=[];
            foreach ($_FILES as $key => $value) {
                if($value['error']!=0) continue;
                $file = request()->file($key);
                // 移动到框架应用根目录/data/uploads/ 目录下
                $url="/data/uploads/";
                $info = $file->validate(['size'=>$size,'ext'=>$ext])->move(ROOT_PATH . 'data' . DS . 'uploads');
                if($info){
                    // 上传成功
                    $savename = str_replace("\\","/",$info->getSaveName());
                    $url=$url.$savename;
                    $urls[]=$url;
                }else{
                    // 上传失败获取错误信息
                    return ['code'=>'40023','msg'=>$file->getError()];
                }
            }
            return ['code'=>0,'msg'=>'上传成功','data'=>$urls];
        }else{
            return ['code'=>'40024','msg'=>'没有上传的文件'];
        }
    }

    /**
     * 生成分页html
     * @param  int $number   总条数
     * @param  int $page     当前页码
     * @param  int $pagesize 每页条数
     * @param  string $align 位置 left right
     * @return string        分页html
     */
    static public function data_list_pages_html($number,$page,$pagesize,$align='right')
    {
        $pagenum  = max(1,ceil($number/$pagesize));
        $prepage  = max(($page-1),1);
        $nextpage = max(1,min(($page+1),$pagenum));
            
        $cururl = preg_replace('/([&\?]?)(page=[0-9]+)([&\?]?)/i','\\1',request()->url());
        $strlen = strlen($cururl)-1;
        $flag   = (boolean)(substr(strrchr($cururl,'/'),1));

        if(substr($cururl,-1,1)=='&')
        {
            $cururl=$flag?substr($cururl,0,$strlen).'&page=':substr($cururl,0,$strlen).'?page=';
        }
        elseif(substr($cururl,-1,1)=='?')
        {
            $cururl=substr($cururl,0,$strlen).'?page=';
        }
        else
        {
            if(strpos($cururl,'?')===false && strpos($cururl,'&')===false)
            {
                $flag=false;
            }

            $cururl=$flag?$cururl.'&page=':$cururl.'?page=';
        }

        $pselect='<select name="pageto" id="pagetoselect" onchange="window.location.href=\''.SITE_PATH.$cururl.'\'+document.getElementById(\'pagetoselect\').value">';
        for($i=1;$i<=intval($pagenum);$i++)
        {
            $pselect.='<option value="'.$i.'">第'.$i.'页</option>';
        }
        $pselect.='</select><script language="javascript">{document.getElementById(\'pagetoselect\').value='.$page.'}</script>';

        return '<div align="'.$align.'">&nbsp;统计共 '.$number.' 条记录 &nbsp;
                    <a href="'.SITE_PATH.$cururl.'1">第一页</a>&nbsp;<a href="'.SITE_PATH.$cururl.$prepage.'">上一页</a>&nbsp;
                    <a href="'.SITE_PATH.$cururl.$nextpage.'">下一页</a>&nbsp;
                    <a href="'.SITE_PATH.$cururl.$pagenum.'">尾页</a>&nbsp;总页数：<font color="#ff0000">'.$page.'</font>/'.$pagenum.'&nbsp;'.$pselect.'
                </div>';
    }
}